import { UnwrapRef } from 'vue'

type IUseRequestOptions<T> = {
  /** 是否立即执行 */
  immediate?: boolean
  /** 初始化数据 */
  initialData?: T
}

type ReturnPromiseType<T> = T extends (arg: any) => Promise<infer P>
  ? P
  : T extends Promise<infer P>
    ? P
    : never

type ReturnPromiseParamsType<T> = T extends (arg: infer P) => Promise<any> ? P : never

/**
 * useRequest是一个定制化的请求钩子，用于处理异步请求和响应。
 * @param func 一个执行异步请求的函数，返回一个包含响应数据的Promise。
 * @param options 包含请求选项的对象 {immediate, initialData}。
 * @param options.immediate 是否立即执行请求，默认为false。
 * @param options.initialData 初始化数据，默认为undefined。
 * @returns 返回一个对象{loading, error, data, run}，包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
 */
export default function useRequest<T>(
  func: () => Promise<IResData<T>>,
  options: IUseRequestOptions<T> = { immediate: false },
) {
  const loading = ref(false)
  const error = ref(false)
  const data = ref<T>(options.initialData)
  const run = async () => {
    loading.value = true
    return func()
      .then((res) => {
        data.value = res.data as UnwrapRef<T>
        error.value = false
        return data.value
      })
      .catch((err) => {
        error.value = err
        throw err
      })
      .finally(() => {
        loading.value = false
      })
  }

  options.immediate && run()
  return { loading, error, data, run }
}

// 过滤null、undefined、空字符串、NaN
const useFilterParams = (params: any, isFilter = false) => {
  return isFilter
    ? Object.entries(params).reduce((prev, [key, val]) => {
        if (val !== null && val !== undefined && val !== '' && !Number.isNaN(val)) {
          prev[key] = val
        }
        return prev
      }, {} as any)
    : params
}

interface PageData extends Record<string, any> {
  page?: number
  size?: number
  total?: number
}
type PageOnlyData<T extends PageData> = Omit<Omit<Omit<T, 'current'>, 'size'>, 'total'>
type GetVal<T extends Record<string, any>> = T extends { [key: string]: (infer P)[] } ? P : never

export const useRequestList = <T extends (p: any) => Promise<PageData>, R>({
  fetchData,
  params,
  dataKey = 'records',
  format,
  pageSize = 20,
  filterParams = false, // 是否开启参数过滤，过滤null、undefined、空字符串
}: {
  /**
   * 请求函数，返回Promise
   * */
  fetchData: T
  params?: Omit<Omit<ReturnPromiseParamsType<T>, 'current'>, 'size'>
  /**
   * 列表的key，默认records
   */
  dataKey?: string
  pageSize?: number
  /**
   * 数据处理
   */
  format: (opt: GetVal<PageOnlyData<ReturnPromiseType<T>>>) => R
  filterParams?: boolean
}) => {
  const list = ref<R[]>([])
  const loading = ref(false)
  const errorMsg = ref('')
  const total = ref(0)
  const p = ref(params)
  const page = ref(1)
  const size = ref(pageSize)
  const isComplete = ref(false)

  const request = async () => {
    const d = { ...(p.value as any), ...{ current: page.value, size: size.value } }
    const fp = useFilterParams(d, filterParams)

    loading.value = true
    try {
      const res = await fetchData(fp)

      list.value = list.value.concat(res[dataKey].map((e: any) => format(e)))
      total.value = res.total!
      errorMsg.value = ''
    } catch (e: any) {
      errorMsg.value = e.message
    }
    if (list.value.length >= total.value) {
      isComplete.value = true
    }
    loading.value = false
  }

  const loadMore = () => {
    if (list.value.length === total.value && total.value === 0) {
      request()
      return
    }

    if (list.value.length < total.value) {
      page.value++
      request()
    }
  }

  const refresh = (data?: Partial<typeof p.value>) => {
    if (data) {
      p.value = { ...(p.value as any), ...data }
    }
    isComplete.value = false
    page.value = 1
    total.value = 0
    list.value = []
    request()
  }

  return {
    isComplete,
    page,
    size,
    list,
    total,
    loading,
    errorMsg,
    loadMore,
    refresh,
  }
}
